package edu.uwosh.cs342.project4;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;

import org.json.JSONArray;
import org.json.JSONObject;

import com.google.android.maps.GeoPoint;
import com.google.android.maps.MapActivity;
import com.google.android.maps.MapController;
import com.google.android.maps.MapView;
import com.google.android.maps.Overlay;


import edu.uwosh.cs342.project4.R;

import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.location.Address;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationListener;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.StrictMode;
import android.os.StrictMode.ThreadPolicy;
import android.view.Menu;
import android.view.MenuInflater;
import android.view.MenuItem;

public class Project4Activity extends MapActivity {
	
	private MapView mapView;
	private List<Overlay> mapOverlays;
	private PositionOverlay chosenLocation, yourLocation;
	private LocationManager locationManager;
	private GeoPoint currentLocation;
	private AddressHelper addressHelper;
	private boolean snapToCurrentLocation = true;
	
	public static final int REQUEST_LOCATION = 1000;
	public static final int RESULT_LOCATION = 1001; 
	public static final int REQUEST_FAVORITES = 2000;
	public static final int RESULT_FAVORITES = 2001;
	//android:apiKey="04JpT6dm_nWXU_-NBkIQKaSoSpilb_vpZVzaKUA"
	
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        
        addressHelper = new AddressHelper();
        
        mapView = (MapView) findViewById(R.id.mapView);
        mapView.setBuiltInZoomControls(true);
        mapView.displayZoomControls(true);
        mapView.setSatellite(false);
        
        mapOverlays = mapView.getOverlays();
        
        //Initiate GPS functionality
        Criteria criteria = new Criteria();
		criteria.setAccuracy(Criteria.ACCURACY_FINE); // fine location data
		criteria.setBearingRequired(true); // need bearing to rotate map
		criteria.setCostAllowed(true); // OK to incur monetary cost
		criteria.setPowerRequirement(Criteria.POWER_LOW); // try to conserve
		criteria.setAltitudeRequired(false); // don't need altitude data

		locationManager = (LocationManager) getSystemService(LOCATION_SERVICE);

		String provider = locationManager.getBestProvider(criteria, true);
		
		locationManager.requestLocationUpdates(provider, 0, 0, new LocationListener(){
			public void onLocationChanged(Location location) {
				if (location != null){
			
					Double latitude = location.getLatitude();
					Double longitude = location.getLongitude();
					String addressLine = "Address unavailable";
					
					GeoPoint myLocation = new GeoPoint((int)(latitude * 1E6), (int)(longitude * 1E6));
					currentLocation = myLocation;
					
					
					try {
						List<Address> addresses = addressHelper.getAddressesFromLocation(Project4Activity.this,
								latitude, longitude);
						if (!addresses.isEmpty())
							addressLine = addressHelper.addressLineBuilder(addresses.get(0));
					} catch (IOException e) {
						e.printStackTrace();
					}
					
					//Clear the previous location from the map overlay list
					if (mapOverlays.contains(yourLocation))
						mapOverlays.remove(yourLocation);
					
					//Load an icon to display on the map, then create and add an overlay to the mapView
					Drawable locationIcon =  getResources().getDrawable(R.drawable.icon_person_small);
					yourLocation = new PositionOverlay(locationIcon, Project4Activity.this);
					yourLocation.setTitle("You Are Here");
					yourLocation.setSnippet(addressLine);
					yourLocation.setChosenLocation(myLocation);
					mapOverlays.add(yourLocation);
					
					
					if (snapToCurrentLocation){
						
						MapController mc = mapView.getController();
						mc.animateTo(myLocation);
						
					}
					
					mapView.invalidate();
				}
			}//end onLocationChanged

			public void onProviderDisabled(String provider) {}

			public void onProviderEnabled(String provider) {}

			public void onStatusChanged(String provider, int status,
					Bundle extras) {}
		});
        
        viewMyLocation();
    }//end onCreate

	@Override
	protected boolean isRouteDisplayed() {
		return false;
	}//end isRouteDisplayed
	
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflater = getMenuInflater();
		inflater.inflate(R.menu.mymenu, menu);
		return true;
	}//end onCreateOptionsMenu
	
	@Override
	public boolean onOptionsItemSelected(MenuItem item) {
		switch (item.getItemId()) {
		case R.id.change_view:
			viewSelection();
			return super.onOptionsItemSelected(item);
		case R.id.my_location:
			viewMyLocation();
			return super.onOptionsItemSelected(item);
		case R.id.find_location:
			setLocation();
			return super.onOptionsItemSelected(item);
		case R.id.favorites:
			favorites();
			return super.onOptionsItemSelected(item);
		default:
			return false;
		}//end case statement
	}//end onOptionsItemSelected
	
	private void viewSelection(){
		AlertDialog viewSelecter;
		CharSequence[] items = {"Satellite View", "Map View"};
		int selectedItem;
		if (mapView.isSatellite())
			selectedItem = 0;
		else
			selectedItem = 1;

		AlertDialog.Builder builder = new AlertDialog.Builder(this);
		builder.setTitle("Select a view mode:");
		builder.setSingleChoiceItems(items, selectedItem, new DialogInterface.OnClickListener() {
		    public void onClick(DialogInterface dialog, int item) {
		        switch (item){
		        case 0: mapView.setSatellite(true);
		        	break;
		        case 1: mapView.setSatellite(false);
		        	break;
		        default:
		        	break;
		        }
		        dialog.dismiss();
		    }
		});
		viewSelecter = builder.create();
		viewSelecter.show();
	}//end viewSelection
	
	private void setLocation(){
		Intent locationChoice = new Intent(Project4Activity.this, SetLocation.class);
		startActivityForResult(locationChoice, REQUEST_LOCATION);
	}//end setLocation
	
	private void viewMyLocation(){
		if (currentLocation != null){
			snapToCurrentLocation = true;
			MapController mc = mapView.getController();
			mc.animateTo(currentLocation);
			mapView.invalidate();
		}
	}//end viewMyLocation
	
	private void favorites(){
		Intent favoritesList = new Intent(Project4Activity.this, FavoritesList.class);
		startActivityForResult(favoritesList, REQUEST_FAVORITES);
	}//end favorites

	
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data){
		List<Place> listOfPlaces;
		if (requestCode == REQUEST_LOCATION && resultCode == RESULT_LOCATION){
			if (data.hasExtra("location") && !data.getStringExtra("location").isEmpty()
					&& data.hasExtra("address")){
				snapToCurrentLocation = false;
				String location = data.getStringExtra("location");
				Address address = data.getParcelableExtra("address");
				MapController mc = mapView.getController();
								
				if (address != null) {
					GeoPoint p = new GeoPoint(
					(int) (address.getLatitude() * 1E6),
					(int) (address.getLongitude() * 1E6));
					mc.animateTo(p);
					autoZoom(address);
					
					//Clear the previous location from the map overlay list
					if (mapOverlays.contains(chosenLocation))
						mapOverlays.clear();
						//mapOverlays.remove(chosenLocation);
					
					//Load an icon to display on the map, then create and add an overlay to the mapView
					Drawable locationIcon = this.getResources().getDrawable(R.drawable.target);
					chosenLocation = new PositionOverlay(locationIcon, this);
					chosenLocation.setTitle("Chosen Location");
					chosenLocation.setSnippet(location);
					chosenLocation.setChosenLocation(p);
					mapOverlays.add(chosenLocation);
					
					
					double radius = 30000;
					radius = Math.pow((20-mapView.getZoomLevel())/2 +4, 4);
					//Find nearby places of interest  using magic voodoo radius formula
					System.out.println("zoom " + mapView.getZoomLevel() + " radius: " + radius + " math " + (25-mapView.getZoomLevel()  ));
					listOfPlaces = 	addPlaces(Double.toString(address.getLatitude()), Double.toString(address.getLongitude()), Double.toString(radius));
					//Drawing the nearby places of interest on map
					for(int i = 0; i < listOfPlaces.size(); i++)
					{	
						AsyncMethod<Project4Activity> getBitmap = new AsyncMethod<Project4Activity>(Project4Activity.class, this, "drawableFromUrl");
						getBitmap.execute(listOfPlaces.get(i).getIcon());
						
						Drawable placeIcon = new BitmapDrawable(getResources(), (Bitmap)getBitmap.getResult());
						//System.out.println(listOfPlaces.get(i).getIcon());
						chosenLocation = new PositionOverlay(placeIcon, this);
						chosenLocation.setTitle(listOfPlaces.get(i).getName());
						StringBuilder description = new StringBuilder();
						description.append("Tags: ");
						for(int a = 0; a< listOfPlaces.get(i).getType().size() 	; a++)
						{
							description.append(listOfPlaces.get(i).getType().get(a));
							if (a != (listOfPlaces.get(i).getType().size() - 1))
								description.append(", ");
						}
						chosenLocation.setSnippet(listOfPlaces.get(i).getAddress() + "\n" +    description.toString()   + "\n" + listOfPlaces.get(i).getPhone());
						Place tempPlace = listOfPlaces.get(i);
						
						;
						GeoPoint Z = new GeoPoint(
								
								(int) ((Double)tempPlace.getGeo().get(0) * 1E6),
								(int) ((Double)tempPlace.getGeo().get(1) * 1E6));
						chosenLocation.setChosenLocation(Z);
						mapOverlays.add(chosenLocation);
						
					}
					
					mapView.invalidate();
				}
			}
		}//end Set Location if block
		else if (requestCode == REQUEST_FAVORITES && resultCode == RESULT_FAVORITES){
			String latitude = "", longitude = "", type = "";
			if (data.hasExtra("latitude"))
				latitude = data.getStringExtra("latitude");
			
			if (data.hasExtra("longitude"))
				longitude = data.getStringExtra("longitude");
			
			if (data.hasExtra("locationType"))
				type = data.getStringExtra("locationType");
			
			if (!latitude.isEmpty() && !longitude.isEmpty()){
				MapController mc = mapView.getController();
				GeoPoint p = new GeoPoint(
				(int) (Double.parseDouble(latitude)),
				(int) (Double.parseDouble(longitude)));
				mc.animateTo(p);
				//autoZoom(address);
			}
		}
	}//end onActivityResult
	
	//place api = AIzaSyB73TiAHKsMGKC5Z34DieRCkXKxY6e8v2k
	public List addPlaces(String lat, String lng, String radius)	
	{
		//https://maps.googleapis.com/maps/api/place/search/json?location=44.02470620,-88.54261360&rankby=distance&types=airport|amusement_park|aquarium|art_gallery|bakery|bar|cafe|campground|car_wash|cemetary|casino|doctor|food|gas_station|gym|hospital|library|lodging|museum|night_club|park|police|restaurant|school|shopping_mall|spa|subway_station|university|zoo&sensor=false&key=AIzaSyB73TiAHKsMGKC5Z34DieRCkXKxY6e8v2k
		//https://maps.googleapis.com/maps/api/place/search/json?location=" +  lat + "," + lng+ "&radius=" + radius + "&sensor=false&key=AIzaSyB73TiAHKsMGKC5Z34DieRCkXKxY6e8v2k"
		 String URL = "https://maps.googleapis.com/maps/api/place/search/json?location=" +  lat + "," 
				 + lng+ "&radius=" + radius + "&types=airport|amusement_park|aquarium|art_gallery|bakery|" + 
				 "bar|cafe|campground|car_wash|cemetary|casino|doctor|food|gas_station|gym|hospital|library|" + 
				 "lodging|museum|night_club|park|police|restaurant|school|shopping_mall|spa|subway_station|" + 
				 "university|zoo&sensor=false&key=AIzaSyB73TiAHKsMGKC5Z34DieRCkXKxY6e8v2k";
         //Connect to google API using Async task
		 AsyncMethod<Project4Activity> am = new AsyncMethod<Project4Activity>(Project4Activity.class, this, "connectMe");
		 am.execute(URL);
		 
		 //Async Task to parse/read JSON results 
		 AsyncMethod<Project4Activity> readJson = new AsyncMethod<Project4Activity>(Project4Activity.class, this, "readJsonStream");
		 readJson.execute(am.getResult());
		 
		 return (List)readJson.getResult();
		
	   
	}
	//Connect to GooglePlaces and Call JSONReader
	public JSONObject connectMe(String URL)
	{
		JSONObject jsonData = null;
		try{
		 String authURL = URL;
		URL url = new URL(authURL);
        HttpURLConnection connection = (HttpURLConnection)url.openConnection();
        //Build JSON Object from string  output from google
		BufferedReader reader = new BufferedReader(new InputStreamReader(connection.getInputStream()));
		StringBuilder sb = new StringBuilder(); 
		String line = reader.readLine();
		
		while (line != null) {
			sb.append(line);
			line = reader.readLine();
		}
		
		reader.close();
		jsonData = new JSONObject(sb.toString());
		return jsonData;
		}
		catch(Exception e)
		{
			System.out.println(e);
		}
		return jsonData; 	   

       

	}
	
	public List<Place> readJsonStream(JSONObject jsonData) 
	{
		List<Place> places = new ArrayList<Place>();
		String phone = "";
		String address = "";
		try{
			
		int i = 0;			
		Place loc;
		JSONArray results = jsonData.getJSONArray("results");
		JSONObject jsonPlaces;
		List<Double> geo;
		List<String> types;
		//Parse the list of nearby locations, storing in list of Place objects
		do
		{   
			jsonPlaces = results.getJSONObject(i);
			geo = new ArrayList<Double>();
			JSONObject jsonLoc = jsonPlaces.getJSONObject("geometry").getJSONObject("location");
			geo.add(jsonLoc.getDouble("lat"));
			geo.add(jsonLoc.getDouble("lng"));
			JSONArray jsonTypes = jsonPlaces.getJSONArray("types");
			types = new ArrayList<String>();
			for (int a = 0; a < jsonTypes.length(); a++)
			{
				types.add(jsonTypes.getString(a));
				
			}
			
			//Pull detailed info for this specific place of interest
			System.out.println("https://maps.googleapis.com/maps/api/place/details/json?reference=" + jsonPlaces.getString("reference") +"&sensor=true&key=AIzaSyB73TiAHKsMGKC5Z34DieRCkXKxY6e8v2k");
			JSONObject details = connectMe("https://maps.googleapis.com/maps/api/place/details/json?reference=" + jsonPlaces.getString("reference") +"&sensor=true&key=AIzaSyB73TiAHKsMGKC5Z34DieRCkXKxY6e8v2k");
			JSONObject detailedResults = details.getJSONObject("result");
			try{
			address = detailedResults.getString("formatted_address");
	
			phone = detailedResults.getString("formatted_phone_number");
			}
			catch(Exception e2){
				System.out.println("Phone or Address does not exist " + e2);
			}
			
			// public Place(long ID, String name, String address, String iconURL, List geo, List type, String phone_number)
			loc = new Place(jsonPlaces.getString("id"), jsonPlaces.getString("name"), address, jsonPlaces.getString("icon"), geo,  types, phone);
			places.add(loc);
			
			i++;
		}while(jsonPlaces != null);
		
		return places;
		}catch(Exception e){
			System.out.println("Exception in parse" + e);
		}
		return places;
	}

	public void autoZoom(Address address){
		MapController mc = mapView.getController();
		
		int zoomLevel = (address.getMaxAddressLineIndex() + 1) * 4;
		
		if (zoomLevel > 15)
			zoomLevel = 15;
		
		mc.setZoom(zoomLevel);
	}//end autoZoom
	
	public Bitmap drawableFromUrl(String url) throws java.net.MalformedURLException, java.io.IOException {
	    Bitmap x;

	    HttpURLConnection connection = (HttpURLConnection)new URL(url) .openConnection();

	    connection.connect();
	    InputStream input = connection.getInputStream();

	    x = BitmapFactory.decodeStream(input);
	    return x;
	}//end drawableFromUrl
}//end class